`include "PRV564Config.v"
`include "PRV564Define.v"
//////////////////////////////////////////////////////////////////////////////////////////////////
//  Date    : 2021                                                                              //
//  Author  : Jack.Pan                                                                          //
//  Desc    : Access table For PRV564 processor                                                 //
//            Access table record all the access issue to memory Access Queue(AQ), kernel use   //
//            this table to keep track in every result.                                         //
//  Version : 0.0(Orignal)                                                                      //
//////////////////////////////////////////////////////////////////////////////////////////////////
module AccessTable(
    input wire              GLB_CLKi,
    input wire              GLB_SRSTi,                  //Sync reset input(Flush use)
//------------------------Empty and FULL signals-----------------
    output wire             Table_Full,
    output wire             Table_Empty,
//-----------------------Access Table write port-----------------
    input wire              Tablei_WREN,
    input wire [7:0]        Tablei_WID,
    input wire [`XLEN-1:0]  Tablei_ADDR,
    input wire [`XLEN-1:0]  Tablei_PC,
    input wire [7:0]        Tablei_ITAG,
    input wire [1:0]        Tablei_priv,
    input wire [7:0]        Tablei_opcode,
    input wire [1:0]        Tablei_opinfo,
    input wire [3:0]        Tablei_opsize,
    input wire              Tablei_ci,
    input wire              Tablei_InstPageFlt,
    input wire              Tablei_LoadPageFlt,
    input wire              Tablei_StorePageFlt,
    input wire              Tablei_InstAddrmis,
    input wire              Tablei_LoadAddrMis,
    input wire              Tablei_StoreAddrMis,
//--------------------Access Table read port----------------------
    input wire              Tablei_RDEN,                //读使能
    input wire [7:0]        Tablei_RID,                 //从Accesstable中读出表项的ID
    input wire              Tablei_Remove,              //移除当前项
    output reg              Tableo_V,                   //当前读出的表项有效
    output reg [`XLEN-1:0]  Tableo_ADDR,
    output reg [`XLEN-1:0]  Tableo_PC,
    output reg [7:0]        Tableo_ITAG,
    output reg [1:0]        Tableo_priv,
    output reg [7:0]        Tableo_opcode,
    output reg [1:0]        Tableo_opinfo,
    output reg [3:0]        Tableo_opsize,
    output reg              Tableo_ci,
    output reg              Tableo_InstPageFlt,
    output reg              Tableo_LoadPageFlt,
    output reg              Tableo_StorePageFlt,
    output reg              Tableo_InstAddrmis,
    output reg              Tableo_LoadAddrMis,
    output reg              Tableo_StoreAddrMis	
);

    reg [3:0]          EntryWrite;                     //Write to an entry
    wire [3:0]          EntryRemove;                    //Remove an entry
    wire [3:0]          Entryo_V;
    wire [7:0]          Entryo_RID		[3:0];
    wire [`XLEN-1:0]    Entryo_ADDR     [3:0];
    wire [`XLEN-1:0]    Entryo_PC       [3:0];
    wire [7:0]          Entryo_ITAG     [3:0];
    wire [1:0]          Entryo_priv     [3:0];
    wire [7:0]          Entryo_opcode   [3:0];
    wire [1:0]          Entryo_opinfo   [3:0];
    wire [3:0]          Entryo_opsize   [3:0];
    wire [3:0]          Entryo_ci;
    wire [3:0]          Entryo_InstPageFlt;
    wire [3:0]          Entryo_LoadPageFlt;
    wire [3:0]          Entryo_StorePageFlt;
    wire [3:0]          Entryo_InstAddrmis;
    wire [3:0]          Entryo_LoadAddrMis;
    wire [3:0]          Entryo_StoreAddrMis;	

//generate 4 Table entry
    genvar i;
    generate
        for(i = 0; i < 4; i=i+1)begin:TableEntry
            TableEntry      TableEntry(
                .GLB_CLKi               (GLB_CLKi),
                .GLB_SRSTi              (GLB_SRSTi),
//-----------------------Access Table write port-----------------
                .Tablei_WREN            (EntryWrite[i]),
                .Tablei_WID             (Tablei_WID),
                .Tablei_ADDR            (Tablei_ADDR),
                .Tablei_PC              (Tablei_PC),
                .Tablei_ITAG            (Tablei_ITAG),
                .Tablei_priv            (Tablei_priv),
                .Tablei_opcode          (Tablei_opcode),
                .Tablei_opinfo          (Tablei_opinfo),
                .Tablei_opsize          (Tablei_opsize),
                .Tablei_ci              (Tablei_ci),
                .Tablei_InstAddrmis     (Tablei_InstAddrmis),
                .Tablei_InstPageFlt     (Tablei_InstPageFlt),
                .Tablei_LoadAddrMis     (Tablei_LoadAddrMis),
                .Tablei_LoadPageFlt     (Tablei_LoadPageFlt),
                .Tablei_StoreAddrMis    (Tablei_StoreAddrMis),
                .Tablei_StorePageFlt    (Tablei_StorePageFlt),
//--------------------Access Table read port----------------------
                .Tablei_Remove          (EntryRemove[i]),
                .Tableo_V               (Entryo_V[i]),
                .Tableo_ADDR            (Entryo_ADDR[i]),
                .Tableo_PC              (Entryo_PC[i]),
                .Tableo_RID             (Entryo_RID[i]),
                .Tableo_ITAG            (Entryo_ITAG[i]),
                .Tableo_priv            (Entryo_priv[i]),
                .Tableo_opcode          (Entryo_opcode[i]),
                .Tableo_opinfo          (Entryo_opinfo[i]),
                .Tableo_opsize          (Entryo_opsize[i]),
                .Tableo_ci              (Entryo_ci[i]),
                .Tableo_InstPageFlt     (Entryo_InstPageFlt[i]),
                .Tableo_LoadPageFlt     (Entryo_LoadPageFlt[i]),
                .Tableo_StorePageFlt    (Entryo_StorePageFlt[i]),
                .Tableo_InstAddrmis     (Entryo_InstAddrmis[i]),
                .Tableo_LoadAddrMis     (Entryo_LoadAddrMis[i]),
                .Tableo_StoreAddrMis    (Entryo_StoreAddrMis[i])				
            );
        end
    endgenerate

//-----------------------------------write to an entry--------------------------------------
always@(*)begin
    if(Tablei_WREN)begin
        if(!Entryo_V[0])begin           //Entry0 是空项
            EntryWrite = 4'b0001;
        end
        else if(!Entryo_V[1])begin
            EntryWrite = 4'b0010;
        end
        else if(!Entryo_V[2])begin
            EntryWrite = 4'b0100;
        end
        else if(!Entryo_V[3])begin
            EntryWrite = 4'b1000;
        end
        else begin
            EntryWrite = 4'b0000;
        end
    end
    else begin
        EntryWrite = 4'b0000;
    end
end
//---------------------------------Remove an entry------------------------------------------
assign EntryRemove[0] = Tablei_Remove & Entryo_V[0] & (Tablei_RID==Entryo_RID[0]);
assign EntryRemove[1] = Tablei_Remove & Entryo_V[1] & (Tablei_RID==Entryo_RID[1]);
assign EntryRemove[2] = Tablei_Remove & Entryo_V[2] & (Tablei_RID==Entryo_RID[2]);
assign EntryRemove[3] = Tablei_Remove & Entryo_V[3] & (Tablei_RID==Entryo_RID[3]);
//------------------------------------Access Table output------------------------------------
always@(*)begin
    if(Entryo_V[0] & Tablei_RDEN & (Tablei_RID==Entryo_RID[0]))begin
        Tableo_V            = 1'b1;
        Tableo_ADDR         = Entryo_ADDR[0];
        Tableo_PC           = Entryo_PC[0];
        Tableo_ITAG         = Entryo_ITAG[0];
        Tableo_priv         = Entryo_priv[0];
        Tableo_opcode       = Entryo_opcode[0];
        Tableo_opinfo       = Entryo_opinfo[0];
        Tableo_opsize       = Entryo_opsize[0];
        Tableo_ci           = Entryo_ci[0];
        Tableo_InstPageFlt  = Entryo_InstPageFlt[0];
        Tableo_LoadPageFlt  = Entryo_LoadPageFlt[0];
        Tableo_StorePageFlt = Entryo_StorePageFlt[0];
        Tableo_InstAddrmis  = Entryo_InstAddrmis[0];
        Tableo_LoadAddrMis  = Entryo_LoadAddrMis[0];
        Tableo_StoreAddrMis = Entryo_StoreAddrMis[0];
    end
    else if(Entryo_V[1] & Tablei_RDEN & (Tablei_RID==Entryo_RID[1]))begin
        Tableo_V            = 1'b1;
        Tableo_ADDR         = Entryo_ADDR[1];
        Tableo_PC           = Entryo_PC[1];
        Tableo_ITAG         = Entryo_ITAG[1];
        Tableo_priv         = Entryo_priv[1];
        Tableo_opcode       = Entryo_opcode[1];
        Tableo_opinfo       = Entryo_opinfo[1];
        Tableo_opsize       = Entryo_opsize[1];
        Tableo_ci           = Entryo_ci[1];
        Tableo_InstPageFlt  = Entryo_InstPageFlt[1];
        Tableo_LoadPageFlt  = Entryo_LoadPageFlt[1];
        Tableo_StorePageFlt = Entryo_StorePageFlt[1];
        Tableo_InstAddrmis  = Entryo_InstAddrmis[1];
        Tableo_LoadAddrMis  = Entryo_LoadAddrMis[1];
        Tableo_StoreAddrMis = Entryo_StoreAddrMis[1];		
    end
    else if(Entryo_V[2] & Tablei_RDEN & (Tablei_RID==Entryo_RID[2]))begin
        Tableo_V            = 1'b1;
        Tableo_ADDR         = Entryo_ADDR[2];
        Tableo_PC           = Entryo_PC[2];
        Tableo_ITAG         = Entryo_ITAG[2];
        Tableo_priv         = Entryo_priv[2];
        Tableo_opcode       = Entryo_opcode[2];
        Tableo_opinfo       = Entryo_opinfo[2];
        Tableo_opsize       = Entryo_opsize[2];
        Tableo_ci           = Entryo_ci[2];
        Tableo_InstPageFlt  = Entryo_InstPageFlt[2];
        Tableo_LoadPageFlt  = Entryo_LoadPageFlt[2];
        Tableo_StorePageFlt = Entryo_StorePageFlt[2];
        Tableo_InstAddrmis  = Entryo_InstAddrmis[2];
        Tableo_LoadAddrMis  = Entryo_LoadAddrMis[2];
        Tableo_StoreAddrMis = Entryo_StoreAddrMis[2];		
    end
    else if(Entryo_V[3] & Tablei_RDEN & (Tablei_RID==Entryo_RID[3]))begin
        Tableo_V            = 1'b1;
        Tableo_ADDR         = Entryo_ADDR[3];
        Tableo_PC           = Entryo_PC[3];
        Tableo_ITAG         = Entryo_ITAG[3];
        Tableo_priv         = Entryo_priv[3];
        Tableo_opcode       = Entryo_opcode[3];
        Tableo_opinfo       = Entryo_opinfo[3];
        Tableo_opsize       = Entryo_opsize[3];
        Tableo_ci           = Entryo_ci[3];
        Tableo_InstPageFlt  = Entryo_InstPageFlt[3];
        Tableo_LoadPageFlt  = Entryo_LoadPageFlt[3];
        Tableo_StorePageFlt = Entryo_StorePageFlt[3];
        Tableo_InstAddrmis  = Entryo_InstAddrmis[3];
        Tableo_LoadAddrMis  = Entryo_LoadAddrMis[3];
        Tableo_StoreAddrMis = Entryo_StoreAddrMis[3];		
    end
    else begin
        Tableo_V            = 1'b0;
        Tableo_ADDR         = 'hx;
        Tableo_PC           = 'hx;
        Tableo_ITAG         = 'hx;
        Tableo_priv         = 'hx;
        Tableo_opcode       = 'hx;
        Tableo_opinfo       = 'hx;
        Tableo_opsize       = 'hx;
        Tableo_ci           = 1'bx;
        Tableo_InstPageFlt  = 'hx;
        Tableo_LoadPageFlt  = 'hx;
        Tableo_StorePageFlt = 'hx;
        Tableo_InstAddrmis  = 'hx;
        Tableo_LoadAddrMis  = 'hx;
        Tableo_StoreAddrMis = 'hx;		
    end
end
//------------------------------Empty and full flag--------------------------------
assign Table_Empty = !(|Entryo_V);
assign Table_Full  = &Entryo_V;

endmodule


